package com.jay.studyproject.interview;

/**
 * Kotlin面试题
 */
public class Demo4 {
    /**
     *
     *
     一、请简述一下什么是Kotlin？它有哪些特性？
     kotlin和java一样也是一门jvm语言最后的编译结果都是.class文件,并且可以通过kotlin的.class文件反编译回去java代码,并且封装了许多语法糖,其中我在项目中常用的特性有
     1.扩展,(使用非集成的方式 扩张一个类的方法和变量):比方说 px和dp之间的转换 之前可能需要写个Util 现在,通过扩展Float的变量 最后调用的时候仅仅是 123.dp 这样px转成dp了
     2.lamdba表达式,函数式编程. lamdba表达式并不是kotlin的专利,java中也有,但是有限制, 像setOnClickListener一样,接口方法只有一个的情况才能调用,
     而在kotlin中对接口的lambda也是如此,有这样的限制,但是他更推荐你使用闭包的方式而不是实现匿名接口的方式去实现这样的功能,
     闭包对lambda没有接口这么多的限制,另外就是函数式编程 在java8中提供了streamApi 对集合进行map sort reduce等等操作,但是对android api有限制,为了兼容低版本,几乎不可能使用streamApi
     3.判空语法 省略了许多if xxx==null 的写法 也避免了空指针异常 aaa?.toString ?: "空空如也" 当aaa为空的时候 它的值被"空空如也"替代 aaa?.let{ it.bbb } 当aaa不为空时 执行括号内的方法
     4.省略了findViewById ,使用kotlin 就可以直接用xml中定义的id 作为变量获取到这个控件,有了这个 butterknife就可以淘汰了,使用databinding也能做到,但是,
     非常遗憾,databinding的支持非常不好,每次修改视图,都不能及时生成,经常要rebulid才能生成.
     5,默认参数 减少方法重载 fun funName(a :Int ,b:Int = 123) 通过如上写法 实际在java中要定义两个写法 funName(a) 和funName(a,b)。

     二、Kotlin 中注解 @JvmOverloads 的作用？
     在Kotlin中@JvmOverloads注解的作用就是：在有默认参数值的方法中使用@JvmOverloads注解，则Kotlin就会暴露多个重载方法。

     三、Kotlin中List与MutableList的区别？
     Kotlin中List、Set、Map与Java中的List、Set、Map有一些不同，kotlin中为只读，只能访问集合中的内容，不能进行修改操作。 如过需要进行添加修改操作需使用Mutable(可变的)前缀

     四、Kotlin中实现单例的几种常见方式？

     五、谈谈你对Kotlin中的 data 关键字的理解？相比于普通类有哪些特点？

     六、什么是委托属性？请简要说说其使用场景和原理？
     类委托： class A: Base by BaseImp() 实现一个接口了正好有一个类可以使用
     属性委托：委托的类需要实现 getValue和setValue 函数加上operator关键字
     委托延迟： by lazy ，lazy内只执行一次，后续只返回结果
     委托工厂：主要需要实现ReadWriteProperty 接口
     属性监听： Delegates.observable 无条件赋值 和Delegates.vetoable (有条件的赋值）

     七、请举例说明Kotlin中with与apply函数的应用场景和区别？
     with` 不怎么使用，因为它确实不防空； 经常使用的是 `run` 和 `apply
     1.run 闭包返回结果是闭包的执行结果；apply 返回的是调用者本身。
     2.使用上的差别：run 更倾向于做一些其他复杂逻辑操作，而 apply 更多的是对调用者自身配置。
     3.大部分情况下，如果不是对调用者本身进行设置，我会使用 run

     八、Kotlin中 Unit 类型的作用以及与Java中Void 的区别？
     1.在java中，必须指定返回类型，即void不能省略，但是在kotlin中，如果返回为unit，可以省略。
     2.java中void为一个关键字，但是在kotlin中unit是一个类

     九、Kotlin 中 infix 关键字的原理和使用场景？
     infix ： 中缀函数，主要使用在只有一个参数的成员函数或者扩展函数上，同时比一般函数具有可读性；
     使用条件：1、函数必须只有一个参数；2、函数必须是扩展函数或者成员函数；3、必须使用infix修饰；

     十、Kotlin中的可见性修饰符有哪些？相比于Java有什么区别？
     kotlin存在四种可见性修饰符，默认是public。 private、protected、internal、public
     1.private、protected、public是和java中的一样的。
     2.不同的是java中默认是default修饰符（包可见），而kotlin存在internal修饰符（模块内部可见）。
     3.kotlin可以直接在文件顶级声明方法、变量等。其中protected不能用来修饰在文件顶级声明的类、方法、变量等。
     构造方法默认是public修饰，可以使用可见性修饰符修饰constructor关键字来改变构造方法的可见性。

     十一、你觉得Kotlin与Java混合开发时需要注意哪些问题？
     Kotlin 默认是非null 类型，java 返回 null，kotlin 需要添加? 表示可为null 2: kotlin 使用!! 时，要确认变量不为null, 不然会直接抛异常

     十二、在Kotlin中，何为解构？该如何使用？
     给一个包含N个组件函数（component）的对象分解为替换等于N个变量的功能，而实现这样功能只需要一个表达式就可以了。
     例如 有时把一个对象解构 成很多变量会很方便，例如: val (name, age) = person 这种语法称为 解构声明 。
     一个解构声明同时创建多个变量。 我们已经声明了两个新变量： name 和 age，并且可以独立使用它们： println(name) println(age)
     一个解构声明会被编译成以下代码： val name = person.component1() val age = person.component2()

     十三、谈谈kotlin中的构造方法？有哪些注意事项？

     1.概要简述
     kotlin中构造函数分为主构造和次级构造两类
     使用关键词constructor标记构造函数，部分情况可省略
     init关键词用于初始化代码块，注意与构造函数的执行顺序，类成员的初始化顺序
     继承，扩展时候的构造函数调用逻辑
     特殊的类如data class、object/componain object、sealed class等构造函数情况与继承问题
     构造函数中的形参声明情况

     2.详细说明
     主/次 构造函数
     kotlin中任何class（包括object/data class/sealed class）都有一个默认的无参构造函数
     如果显式的声明了构造函数，默认的无参构造函数就失效了。
     主构造函数写在class声明处，可以有访问权限修饰符private,public等，且可以省略constructor关键字。
     若显式的在class内声明了次级构造函数，就需要委托调用主构造函数。
     若在class内显式的声明处所有构造函数（也就是没有了所谓的默认主构造），这时候可以不用依次调用主构造函数。例如继承View实现自定义控件时，三四个构造函数同时显示声明。
     init初始化代码块
     kotlin中若存在主构造函数，其不能有代码块执行，init起到类似作用，在类初始化时侯执行相关的代码块。
     init代码块优先于次级构造函数中的代码块执行。
     即使在类的继承体系中，各自的init也是优先于构造函数执行。
     在主构造函数中，形参加有var/val，那么就变成了成员属性的声明。这些属性声明是早于init代码块的。
     特殊类
     object/companion object是对象示例，作为单例类或者伴生对象，没有构造函数。
     data class要求必须有一个含有至少一个成员属性的主构造函数，其余方面和普通类相同。
     sealed class只是声明类似抽象类一般，可以有主构造函数，含参无参以及次级构造等。

     十四、谈谈Kotlin中的Sequence，为什么它处理集合操作更加高效？
     每一步操作之间不会产生临时数据
     由于可以直接得到单个元素的最终结果, 所以减少运算次数, 如上图, map 只进行了 2 次
     补充: 也有例外, 当只有一次操作时, 比如 只 进行 filter or average or sum ...等, List 的效率是要高于 Sequence 的

     十五、请谈谈Kotlin中的Coroutines，它与线程有什么区别？有哪些优点？
     1，在单个进程内，多个协程串行执行，只挂起不阻塞
     2，协程最终的执行还是在各个线程之中
     优点：
     1，由于不阻塞线程，异步任务是编译器主动交到线程池中执行。因此，在异步任务执行上，切换和消耗的资源都较少。
     2，由于协程是跨多个线程，并且能够保持串行执行；因此，在处理多并发的情况上，能够比锁更轻量级。通过状态量实现

     十六、Kotlin中该如何安全地处理可空类型？

     十七、说说Kotlin中的Any与Java中的Object有何异同？
     都是顶级父类
     异：成员方法不同 Any只声明了toString()、hashCode()和equals()作为成员方法。

     十八、Kotlin中的数据类型有隐式转换吗？为什么？
     kotlin中没有所谓的'基本类型'，本质上不存在拆装箱过程，所有的基本类型都可以想象成Java中的包装类型，所以也不存在隐式转换，对应的都是强类型，一旦声明之后，所有转换都是显示转换。

     十九、Kotlin中集合遍历有哪几种方式？

     二十、为什么协程比线程要轻量？
     ·  编码复杂度: kotlin 提供了优秀的编译机制, 写法上我就不多说了, 的确很简单就是了， 可以搜索kotlin 协程原理
     ·  性能消耗:
     2.1 在不考虑线程池的情况下， 我们基本上是每个任务创建一个线程,，那么这个时候协程肯定是比线程轻量的；因为协程内部是由线程池来执行的
     2.2 考虑线程池的情况：没有差异： 协程再某些情况下会因为额外的线程切换导致更多的性能消耗

     二十一、分别通过对象表达式object 和 lambda 表达式实现的函数式接口内部有何不同？
     1. object是匿名内部类的形式，匿名内部类是在编译后形成一个class
     2. Lambda表达式是在程序运行的时候动态生成class

     二十二、在Kotlin 中，什么是内联函数？有什么作用？
     对比java 函数反复调用时，会有压栈出栈的性能消耗
     kotlin优化 内联函数 用来解决 频繁调用某个函数导致的性能消耗
     使用inline标记 内联函数，调用非内联函数会报错，，需要加上noinline标记
     noinline，让原本的内联函数形参函数不是内联的，保留原有数据特征
     crossinline 非局部返回标记 为了不让lamba表达式直接返回内联函数，所做的标记
     相关知识点：我们都知道,kotlin中,如果一个函数中,存在一个lambda表达式，在该lambda中不支持直接通过return退出该函数的,只能通过return@XXXinterface这种方式
     reified 具体化泛型 java中，不能直接使用泛型的类型 kotlin可以直接使用泛型的类型
     使用内联标记的函数，这个函数的泛型，可以具体化展示，所有能解决方法重复的问题
     */
}
